From 8733e2a918c9ce244fb00bc28623436ec98c23ca Mon Sep 17 00:00:00 2001 From: Carlos Garnacho Date: Thu, 17 Jan 2013 21:02:28 +0100 Subject: [PATCH] Add GtkGestureSwipe This gesture implementation recognices swipes on any direction. The "swipe" signal has the X/Y velocity vector components, so those can be used for direction guessing and velocity thresholds. --- gtk/Makefile.am | 2 + gtk/gtk.h | 1 + gtk/gtkgestureswipe.c | 201 ++++++++++++++++++++++++++++++++++++++++++ gtk/gtkgestureswipe.h | 67 ++++++++++++++ 4 files changed, 271 insertions(+) create mode 100644 gtk/gtkgestureswipe.c create mode 100644 gtk/gtkgestureswipe.h diff --git a/gtk/Makefile.am b/gtk/Makefile.am index 2abd9efa8f..acdc0997b1 100644 --- a/gtk/Makefile.am +++ b/gtk/Makefile.am @@ -282,6 +282,7 @@ gtk_public_h_sources = \ gtkframe.h \ gtkgesture.h \ gtkgesturelongpress.h \ + gtkgestureswipe.h \ gtkgrid.h \ gtkheaderbar.h \ gtkicontheme.h \ @@ -776,6 +777,7 @@ gtk_base_c_sources = \ gtkgladecatalog.c \ gtkgesture.c \ gtkgesturelongpress.c \ + gtkgestureswipe.c \ gtkgrid.c \ gtkheaderbar.c \ gtkhsla.c \ diff --git a/gtk/gtk.h b/gtk/gtk.h index 6ff01b6fad..075ed304c0 100644 --- a/gtk/gtk.h +++ b/gtk/gtk.h @@ -108,6 +108,7 @@ #include #include #include +#include #include #include #include diff --git a/gtk/gtkgestureswipe.c b/gtk/gtkgestureswipe.c new file mode 100644 index 0000000000..d912703df6 --- /dev/null +++ b/gtk/gtkgestureswipe.c @@ -0,0 +1,201 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 2012, One Laptop Per Child. + * Copyright (C) 2014, Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + * + * Author(s): Carlos Garnacho + */ +#include "config.h" +#include +#include "gtkmarshalers.h" + +#define CAPTURE_THRESHOLD_MS 150 + +typedef struct _GtkGestureSwipePrivate GtkGestureSwipePrivate; +typedef struct _EventData EventData; + +struct _EventData +{ + guint32 evtime; + GdkPoint point; +}; + +struct _GtkGestureSwipePrivate +{ + GArray *events; +}; + +enum { + SWIPE, + N_SIGNALS +}; + +static guint signals[N_SIGNALS] = { 0 }; + +G_DEFINE_TYPE_WITH_PRIVATE (GtkGestureSwipe, gtk_gesture_swipe, GTK_TYPE_GESTURE) + +static void +gtk_gesture_swipe_finalize (GObject *object) +{ + GtkGestureSwipePrivate *priv; + + priv = gtk_gesture_swipe_get_instance_private (GTK_GESTURE_SWIPE (object)); + g_array_free (priv->events, TRUE); + + G_OBJECT_CLASS (gtk_gesture_swipe_parent_class)->finalize (object); +} + +static void +_gtk_gesture_swipe_clear_backlog (GtkGestureSwipe *gesture, + guint32 evtime) +{ + GtkGestureSwipePrivate *priv; + gint i, length = 0; + + priv = gtk_gesture_swipe_get_instance_private (gesture); + + for (i = 0; i < (gint) priv->events->len; i++) + { + EventData *data; + + data = &g_array_index (priv->events, EventData, i); + + if (data->evtime >= evtime - CAPTURE_THRESHOLD_MS) + { + length = i - 1; + break; + } + } + + if (length > 0) + g_array_remove_range (priv->events, 0, length); +} + +static void +gtk_gesture_swipe_update (GtkGesture *gesture, + GdkEventSequence *sequence) +{ + GtkGestureSwipe *swipe = GTK_GESTURE_SWIPE (gesture); + GtkGestureSwipePrivate *priv; + EventData new; + gdouble x, y; + + priv = gtk_gesture_swipe_get_instance_private (swipe); + gtk_gesture_get_last_update_time (gesture, sequence, &new.evtime); + gtk_gesture_get_point (gesture, sequence, &x, &y); + + new.point.x = x; + new.point.y = y; + + _gtk_gesture_swipe_clear_backlog (swipe, new.evtime); + g_array_append_val (priv->events, new); +} + +static void +_gtk_gesture_swipe_calculate_velocity (GtkGestureSwipe *gesture, + gdouble *velocity_x, + gdouble *velocity_y) +{ + GtkGestureSwipePrivate *priv; + EventData *start, *end; + gdouble diff_x, diff_y; + guint32 diff_time; + + priv = gtk_gesture_swipe_get_instance_private (gesture); + *velocity_x = *velocity_y = 0; + + if (priv->events->len == 0) + return; + + start = &g_array_index (priv->events, EventData, 0); + end = &g_array_index (priv->events, EventData, priv->events->len - 1); + + diff_time = end->evtime - start->evtime; + diff_x = end->point.x - start->point.x; + diff_y = end->point.y - start->point.y; + + if (diff_time == 0) + return; + + /* Velocity in pixels/sec */ + *velocity_x = diff_x * 1000 / diff_time; + *velocity_y = diff_y * 1000 / diff_time; +} + +static void +gtk_gesture_swipe_end (GtkGesture *gesture, + GdkEventSequence *sequence) +{ + GtkGestureSwipe *swipe = GTK_GESTURE_SWIPE (gesture); + GtkGestureSwipePrivate *priv; + gdouble velocity_x, velocity_y; + guint32 evtime; + + priv = gtk_gesture_swipe_get_instance_private (swipe); + gtk_gesture_get_last_update_time (gesture, sequence, &evtime); + _gtk_gesture_swipe_clear_backlog (swipe, evtime); + _gtk_gesture_swipe_calculate_velocity (swipe, &velocity_x, &velocity_y); + g_signal_emit (gesture, signals[SWIPE], 0, velocity_x, velocity_y); + + if (priv->events->len > 0) + g_array_remove_range (priv->events, 0, priv->events->len); +} + +static void +gtk_gesture_swipe_class_init (GtkGestureSwipeClass *klass) +{ + GtkGestureClass *gesture_class = GTK_GESTURE_CLASS (klass); + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->finalize = gtk_gesture_swipe_finalize; + + gesture_class->update = gtk_gesture_swipe_update; + gesture_class->end = gtk_gesture_swipe_end; + + signals[SWIPE] = + g_signal_new ("swipe", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GtkGestureSwipeClass, swipe), + NULL, NULL, NULL, + G_TYPE_NONE, 2, G_TYPE_DOUBLE, G_TYPE_DOUBLE); +} + +static void +gtk_gesture_swipe_init (GtkGestureSwipe *gesture) +{ + GtkGestureSwipePrivate *priv; + + priv = gtk_gesture_swipe_get_instance_private (gesture); + priv->events = g_array_new (FALSE, FALSE, sizeof (EventData)); +} + +/** + * gtk_gesture_swipe_new: + * @widget: a #GtkWidget + * + * Returns a newly created #GtkGesture that recognizes swipes + * + * Returns: a newly created #GtkGestureSwipe + * + * Since: 3.14 + **/ +GtkGesture * +gtk_gesture_swipe_new (GtkWidget *widget) +{ + return g_object_new (GTK_TYPE_GESTURE_SWIPE, + "widget", widget, + NULL); +} diff --git a/gtk/gtkgestureswipe.h b/gtk/gtkgestureswipe.h new file mode 100644 index 0000000000..5806bb4367 --- /dev/null +++ b/gtk/gtkgestureswipe.h @@ -0,0 +1,67 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 2012, One Laptop Per Child. + * Copyright (C) 2014, Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + * + * Author(s): Carlos Garnacho + */ +#ifndef __GTK_GESTURE_SWIPE_H__ +#define __GTK_GESTURE_SWIPE_H__ + +#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION) +#error "Only can be included directly." +#endif + +#include +#include + +G_BEGIN_DECLS + +#define GTK_TYPE_GESTURE_SWIPE (gtk_gesture_swipe_get_type ()) +#define GTK_GESTURE_SWIPE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GTK_TYPE_GESTURE_SWIPE, GtkGestureSwipe)) +#define GTK_GESTURE_SWIPE_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), GTK_TYPE_GESTURE_SWIPE, GtkGestureSwipeClass)) +#define GTK_IS_GESTURE_SWIPE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GTK_TYPE_GESTURE_SWIPE)) +#define GTK_IS_GESTURE_SWIPE_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GTK_TYPE_GESTURE_SWIPE)) +#define GTK_GESTURE_SWIPE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GTK_TYPE_GESTURE_SWIPE, GtkGestureSwipeClass)) + +typedef struct _GtkGestureSwipe GtkGestureSwipe; +typedef struct _GtkGestureSwipeClass GtkGestureSwipeClass; + +struct _GtkGestureSwipe +{ + GtkGesture parent_instance; +}; + +struct _GtkGestureSwipeClass +{ + GtkGestureClass parent_class; + + void (* swipe) (GtkGestureSwipe *gesture, + gdouble velocity_x, + gdouble velocity_y); + + /*< private >*/ + gpointer padding[10]; +}; + +GDK_AVAILABLE_IN_3_14 +GType gtk_gesture_swipe_get_type (void) G_GNUC_CONST; + +GDK_AVAILABLE_IN_3_14 +GtkGesture * gtk_gesture_swipe_new (GtkWidget *widget); + +G_END_DECLS + +#endif /* __GTK_GESTURE_SWIPE_H__ */ -- 2.30.2